/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.service.evaluation;

import cn.ac.nercis.pes.common.constant.common.AssetConstants;
import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.common.TargetConstants;
import cn.ac.nercis.pes.common.constant.knowledge.*;
import cn.ac.nercis.pes.common.utils.ConvertUtils;
import cn.ac.nercis.pes.common.utils.DataUtils;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationModule;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.common.constant.project.RefTargetType;
import cn.ac.nercis.pes.common.constant.project.SpecialType;
import cn.ac.nercis.pes.common.constant.rules.KeyDataReqTargetRule;
import cn.ac.nercis.pes.common.constant.rules.PhySecurityReqTargetRule;
import cn.ac.nercis.pes.common.constant.rules.SubBusinessReqTargetRule;
import cn.ac.nercis.pes.model.dto.common.ItemData;
import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.dto.common.TreeNode;
import cn.ac.nercis.pes.model.dto.evaluation.planning.AssetEvaluationMethodDTO;
import cn.ac.nercis.pes.model.dto.evaluation.planning.AssetLayerEvalMethodDTO;
import cn.ac.nercis.pes.model.dto.evaluation.planning.AssetUnitEvalMethodDTO;
import cn.ac.nercis.pes.model.dto.evaluation.planning.RelatedTargetDTO;
import cn.ac.nercis.pes.model.dto.knowledge.KmSimpleTargetDTO;
import cn.ac.nercis.pes.repository.dal.evaluation.AssetEvaluationDescRepository;
import cn.ac.nercis.pes.repository.dal.evaluation.AssetEvaluationMethodRepository;
import cn.ac.nercis.pes.repository.dal.evaluation.AssetRepository;
import cn.ac.nercis.pes.repository.dal.evaluation.EvaluationRecordRepository;
import cn.ac.nercis.pes.repository.dal.knowledge.KmAssetClassRepository;
import cn.ac.nercis.pes.repository.dal.knowledge.KmEvaluationMethodRepository;
import cn.ac.nercis.pes.repository.dal.manage.ConstantRepository;
import cn.ac.nercis.pes.repository.dal.project.SystemSpecialTargetRepository;
import cn.ac.nercis.pes.repository.dal.project.SystemTargetRepository;
import cn.ac.nercis.pes.repository.mapper.evaluation.EvaluationRangeMapper;
import cn.ac.nercis.pes.repository.mapper.project.SystemTargetMapper;
import cn.ac.nercis.pes.repository.model.evaluation.AssetDO;
import cn.ac.nercis.pes.repository.model.evaluation.AssetEvaluationDescDO;
import cn.ac.nercis.pes.repository.model.evaluation.AssetEvaluationMethodDO;
import cn.ac.nercis.pes.repository.model.knowledge.KmAssetClassDO;
import cn.ac.nercis.pes.repository.model.knowledge.KmEvaluationMethodDO;
import cn.ac.nercis.pes.repository.model.manage.ConstantDO;
import cn.ac.nercis.pes.repository.model.project.SystemSpecialTargetDO;
import cn.ac.nercis.pes.repository.model.project.SystemTargetDO;
import cn.ac.nercis.pes.repository.utils.DbUtils;
import cn.ac.nercis.pes.service.manage.ProcessRelatedService;
import cn.ac.nercis.pes.service.project.SystemProcessService;
import cn.ac.nercis.pes.service.utils.AssetUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 测评范围服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public record EvaluationRangeService(KmAssetClassRepository kmAssetClassRepository,
                                     KmEvaluationMethodRepository kmEvaluationMethodRepository,
                                     AssetRepository assetRepository,
                                     SystemTargetRepository systemTargetRepository,
                                     SystemSpecialTargetRepository systemSpecialTargetRepository,
                                     AssetEvaluationMethodRepository evaluationMethodRepository,
                                     AssetEvaluationDescRepository evaluationDescRepository,
                                     ConstantRepository constantRepository,
                                     EvaluationRecordRepository evaluationRecordRepository,
                                     ProcessRelatedService processRelatedService,
                                     SystemProcessService systemProcessService) {

    private static final String TEMPLATE_CONSTANT_SUFFIX = "_测评方式说明";
    private static final String ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX = "_默认指标";

    @Autowired
    public EvaluationRangeService {
    }

    /**
     * 获取资产树节点
     * 第一级节点：资产分类信息
     * 第二级节点：资产对象信息
     *
     * @param systemId 系统ID
     * @return 资产树节点列表
     */
    public Result<List<TreeNode>> findAssetTree(@NonNull String systemId) {
        Integer systemTargetCount = systemTargetRepository.countAllBySystemId(systemId);
        if (systemTargetCount == 0) {
            return Result.failed(ResultCode.EMPTY_SYSTEM_TARGET_DATA);
        }
        List<AssetDO> assets = assetRepository.findAllBySystemId(systemId);
        if (CollectionUtils.isEmpty(assets)) {
            return Result.failed(ResultCode.EMPTY_SYSTEM_ASSET_DATA);
        }
        var evaluationMethods = evaluationMethodRepository.findAllBySystemId(systemId);
        try {
            List<TreeNode> nodes = Arrays.stream(VirtualClassification.values())
                    .map(ac -> TreeNode.builder()
                            .id(ac.getId())
                            .name(ac.getName())
                            .children(findAssetTree(ac.getClassIds(), assets, evaluationMethods))
                            .build())
                    .collect(Collectors.toList());
            return Result.success(nodes);
        } catch (Exception ex) {
            log.error("获取资产树节点出错：", ex);
            return Result.failed("获取系统资产信息失败");
        }
    }

    /**
     * 获取指定的资产树节点
     * 第一级节点：资产分类信息
     * 第二级节点：资产对象信息
     *
     * @param systemId 系统ID
     * @return 资产树节点列表
     */
    public Result<TreeNode> getAssetTreeNode(@NonNull String systemId, @NonNull String assetId) {
        AssetDO assetDO = assetRepository.findById(assetId).orElse(null);
        if (Objects.isNull(assetDO)) {
            return Result.failed(ResultCode.ASSET_NOT_EXIST);
        }
        List<AssetEvaluationMethodDO> evaluationMethods = evaluationMethodRepository.findAllBySystemIdAndAssetId(systemId, assetId);
        return Result.success(TreeNode.builder()
                .id(assetDO.getId())
                .name(AssetUtils.getAssetName(assetDO))
                .data(getAssetFinishState(assetDO, evaluationMethods))
                .build());
    }

    /**
     * 修复重复数据
     */
    public void repairDuplicateData(@NonNull String systemId, @NonNull String assetId) {
        var evaluationMethods = evaluationMethodRepository.findAllBySystemIdAndAssetId(systemId, assetId);
        var unitTargetIds = evaluationMethods.stream()
                .map(AssetEvaluationMethodDO::getUnitTargetId)
                .collect(Collectors.toSet());
        List<AssetEvaluationMethodDO> duplicateData = new ArrayList<>();
        for (var unitTargetId : unitTargetIds) {
            var records = evaluationMethods.stream()
                    .filter(er -> StringUtils.equals(er.getUnitTargetId(), unitTargetId))
                    .toList();
            duplicateData.addAll(DbUtils.findDuplicateData(records));
        }
        if (CollectionUtils.isNotEmpty(duplicateData)) {
            this.processRelatedService.deleteAssetRelateTargetRelatedData(duplicateData);
            this.evaluationMethodRepository.deleteAll(duplicateData);
        }
    }

    /**
     * 获取资产对象关联的层面指标
     *
     * @param systemId 系统ID
     * @param assetId  资产对象ID
     * @return 层面指标信息列表
     */
    public Result<List<KmSimpleTargetDTO>> findLayerTargetByAsset(@NonNull String systemId, @NonNull String assetId) {
        this.repairDuplicateData(systemId, assetId);
        Set<String> layerTargetIds = evaluationMethodRepository.findAllBySystemIdAndAssetId(systemId, assetId)
                .stream()
                .map(AssetEvaluationMethodDO::getLayerTargetId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(layerTargetIds)) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        List<KmSimpleTargetDTO> layerTargets = systemTargetRepository.findAllBySystemIdAndKmTargetIdIn(systemId,layerTargetIds)
                .stream()
                .sorted(Comparator.comparingInt(SystemTargetDO::getKmSort))
                .map(SystemTargetMapper.INSTANCE::toSimpleTargetDTO)
                .collect(Collectors.toList());
        return Result.success(layerTargets);
    }

    public RelatedTargetDTO getRelatedTarget(@NonNull String systemId, @NonNull String assetId) {
        List<String> unitTargetIds = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(systemId, assetId)
                .stream()
                .map(AssetEvaluationMethodDO::getUnitTargetId)
                .collect(Collectors.toList());
        return RelatedTargetDTO.builder()
                .systemId(systemId)
                .assetId(assetId)
                .unitTargetIds(unitTargetIds)
                .build();
    }

    public Result<String> checkRelatedTarget(@NonNull RelatedTargetDTO relatedTarget) {
        var evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(
                relatedTarget.getSystemId(), relatedTarget.getAssetId());
        if (CollectionUtils.isEmpty(evaluationMethods)) {
            return Result.success();
        }
        var deletedEvaluationMethods = evaluationMethods.stream()
                .filter(em -> relatedTarget.getUnitTargetIds().stream().noneMatch(id -> StringUtils.equals(em.getUnitTargetId(), id)))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(deletedEvaluationMethods)) {
            return Result.success();
        }
        boolean hasRelated = evaluationRecordRepository.findAllBySystemIdAndAsset(relatedTarget.getSystemId(),
                        AssetDO.builder().id(relatedTarget.getAssetId()).build())
                .stream()
                .anyMatch(er -> deletedEvaluationMethods.stream().anyMatch(em -> StringUtils.equals(er.getAssetEvaMethodId(), em.getId())));
        if (hasRelated) {
            return Result.failed("当前对象将要取消关联的指标下存在测评数据，是否继续进行保存？");
        } else {
            return Result.success();
        }
    }

    public synchronized Result<String> saveRelatedTarget(@NonNull RelatedTargetDTO relatedTarget) {
        if (CollectionUtils.isEmpty(relatedTarget.getUnitTargetIds())) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        var evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(
                relatedTarget.getSystemId(), relatedTarget.getAssetId());
        Result<String> result = this.removeRelateTarget(relatedTarget, evaluationMethods);
        if (!result.isSuccess()) {
            return result;
        }
        AssetClassification ac = assetRepository.findById(relatedTarget.getAssetId())
                .map(a -> AssetClassification.fromId(a.getClassId()))
                .orElse(null);
        if (CollectionUtils.isNotEmpty(evaluationMethods) && Objects.nonNull(ac)) {
            if (ac == AssetClassification.KEY_DATA) {
                systemProcessService.setSystemProcess(relatedTarget.getSystemId(), EvaluationModule.ASSET_KEY_DATA, FinishState.INCOMPLETE);
            } else if (ac == AssetClassification.KEY_BUSINESS || ac == AssetClassification.SUB_BUSINESS) {
                systemProcessService.setSystemProcess(relatedTarget.getSystemId(), EvaluationModule.ASSET_KEY_BUSINESS, FinishState.INCOMPLETE);
            }
        }
        return createRelateTarget(relatedTarget, evaluationMethods);
    }

    public boolean isRelatedTarget(@NonNull String assetId) {
        return this.evaluationMethodRepository.existsByAssetId(assetId);
    }

    public Result<AssetLayerEvalMethodDTO> getLayerEvalMethod(@NonNull String systemId, @NonNull String assetId,
                                                              @NonNull String layerTargetId){
        var evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetIdAndLayerTargetId(systemId,
                assetId, layerTargetId);
        if (CollectionUtils.isEmpty(evaluationMethods)) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        var evaluationDesc = evaluationDescRepository.findAllBySystemIdAndAssetId(systemId,assetId)
                .stream()
                .filter(ed->StringUtils.equals(ed.getLayerTargetId(),layerTargetId))
                .findFirst()
                .orElse(null);
        var unitTargetNames = findUnitTargetNames(systemId,evaluationMethods);
        var assetLayerEvalMethod = AssetLayerEvalMethodDTO.builder()
                .systemId(systemId)
                .assetId(assetId)
                .layerTargetId(layerTargetId)
                .unitTarget(String.join(BaseConstants.WORD_MULTI_JOIN_CHAR,unitTargetNames))
                .build();
        if(Objects.nonNull(evaluationDesc)){
            assetLayerEvalMethod.setId(evaluationDesc.getId());
            assetLayerEvalMethod.setMethod(evaluationDesc.getMethod());
            assetLayerEvalMethod.setDesc(evaluationDesc.getDesc());
            assetLayerEvalMethod.setFinishState(evaluationDesc.getFinishState());
        }else{
            evaluationMethods.stream().findFirst()
                    .ifPresent(aem -> {
                        assetLayerEvalMethod.setMethod(aem.getMethod());
                        assetLayerEvalMethod.setDesc(aem.getDesc());
                        assetLayerEvalMethod.setFinishState(aem.getFinishState());
                    });
        }
        return Result.success(assetLayerEvalMethod);
    }

    public Result<String> saveLayerEvalMethod(@NonNull AssetLayerEvalMethodDTO evaluationMethod, @NonNull FinishState state) {
        var syncResult = syncUnitEvalMethod(evaluationMethod,state);
        if(!syncResult.isSuccess()){
            return syncResult;
        }
        var evaluationDesc = evaluationDescRepository.findAllBySystemIdAndAssetId(evaluationMethod.getSystemId(),evaluationMethod.getAssetId())
                .stream()
                .filter(ed->StringUtils.equals(ed.getLayerTargetId(),evaluationMethod.getLayerTargetId()))
                .findFirst()
                .orElse(null);
        if(Objects.isNull(evaluationDesc)){
            return createLayerEvalMethod(evaluationMethod);
        }else{
            return modifyLayerEvalMethod(evaluationDesc,evaluationMethod);
        }
    }

    public Result<AssetUnitEvalMethodDTO> getUnitEvalMethod(@NonNull String systemId, @NonNull String assetId,
                                                            @NonNull String unitTargetId){
        var evaluationMethod = this.evaluationMethodRepository.findBySystemIdAndAssetIdAndUnitTargetId(systemId, assetId, unitTargetId)
                .stream().findFirst().orElse(null);
        if (Objects.isNull(evaluationMethod)) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        var unitTargetNames = findUnitTargetNames(systemId,List.of(evaluationMethod));
        var assetLayerEvalMethod = AssetUnitEvalMethodDTO.builder()
                .id(evaluationMethod.getId())
                .systemId(systemId)
                .assetId(assetId)
                .layerTargetId(evaluationMethod.getLayerTargetId())
                .unitTargetId(evaluationMethod.getUnitTargetId())
                .unitTargetName(String.join(BaseConstants.WORD_MULTI_JOIN_CHAR,unitTargetNames))
                .method(evaluationMethod.getMethod())
                .finishState(evaluationMethod.getFinishState())
                .build();
        if(StringUtils.isNotBlank(evaluationMethod.getDesc())){
            assetLayerEvalMethod.setDesc(evaluationMethod.getDesc());
        }else{
            assetLayerEvalMethod.setDesc(getKmEvalMethod(evaluationMethod.getUnitTargetId(),evaluationMethod.getRefType(),evaluationMethod.getMethod()));
        }
        return Result.success(assetLayerEvalMethod);
    }

    public Result<String> getKmEvalMethod(@NonNull String systemId, @NonNull String assetId,
                                          @NonNull String unitTargetId){
        var evaluationMethod = this.evaluationMethodRepository.findBySystemIdAndAssetIdAndUnitTargetId(systemId,
                assetId, unitTargetId).stream().findFirst().orElse(null);
        if (Objects.isNull(evaluationMethod)) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        return Result.success(getKmEvalMethod(evaluationMethod.getUnitTargetId(),evaluationMethod.getRefType(),evaluationMethod.getMethod()));
    }

    public Result<String> saveUnitEvalMethod(@NonNull AssetUnitEvalMethodDTO evaluationMethod, @NonNull FinishState state){
        var evaluationMethods = this.evaluationMethodRepository.findBySystemIdAndAssetIdAndUnitTargetId(evaluationMethod.getSystemId(),
                evaluationMethod.getAssetId(), evaluationMethod.getUnitTargetId());
        if (CollectionUtils.isEmpty(evaluationMethods)) {
            return Result.failed(ResultCode.EMPTY_ASSET_TARGET_RELATED);
        }
        evaluationMethods.forEach(aem -> {
            aem.setMethod(evaluationMethod.getMethod());
            aem.setDesc(evaluationMethod.getDesc());
            aem.setFinishState(state);
            aem.setModifyTime(LocalDateTime.now());
        });
        evaluationMethodRepository.saveAll(evaluationMethods);
        return Result.success();
    }

    public List<AssetUnitEvalMethodDTO> findUnitEvalMethods(@NonNull String systemId, @NonNull String assetId,
                                                            @NonNull String layerTargetId){
        var evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetIdAndLayerTargetId(systemId,
                assetId, layerTargetId);
        if (CollectionUtils.isEmpty(evaluationMethods)) {
            return Collections.emptyList();
        }
        var unitTargets = findUnitTargetData(systemId,evaluationMethods);
        return evaluationMethods.stream()
                .map(em->AssetUnitEvalMethodDTO.builder()
                        .id(em.getId())
                        .systemId(systemId)
                        .assetId(assetId)
                        .layerTargetId(em.getLayerTargetId())
                        .unitTargetId(em.getUnitTargetId())
                        .unitTargetName(unitTargets.stream()
                                .filter(ut->StringUtils.equals(ut.getValue(),em.getUnitTargetId()))
                                .map(ItemData::getName).findFirst()
                                .orElse(StringUtils.EMPTY))
                        .method(em.getMethod())
                        .finishState(em.getFinishState())
                        .build())
                .toList();
    }

    public void saveUnitEvalMethods(List<AssetUnitEvalMethodDTO> evalMethods){
        for(var item : evalMethods){
            saveUnitEvalMethod(item,item.getFinishState());
        }
    }

    private Result<String> createLayerEvalMethod(AssetLayerEvalMethodDTO evaluationMethod){
        return Optional.of(EvaluationRangeMapper.INSTANCE.toDO(evaluationMethod))
                .map(e->{
                    e.setCreateTime(LocalDateTime.now());
                    return e;
                })
                .map(evaluationDescRepository::save)
                .map(AssetEvaluationDescDO::getId)
                .map(Result::success)
                .orElse(Result.failed());
    }

    private Result<String> modifyLayerEvalMethod(AssetEvaluationDescDO entity,AssetLayerEvalMethodDTO evaluationMethod){
        entity.setMethod(evaluationMethod.getMethod());
        entity.setDesc(evaluationMethod.getDesc());
        entity.setFinishState(evaluationMethod.getFinishState());
        entity.setModifyTime(LocalDateTime.now());
        return Optional.of(evaluationDescRepository.save(entity))
                .map(AssetEvaluationDescDO::getId)
                .map(Result::success)
                .orElse(Result.failed());
    }

    private Result<String> syncUnitEvalMethod(@NonNull AssetLayerEvalMethodDTO evaluationMethod, @NonNull FinishState state){
        var evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetIdAndLayerTargetId(evaluationMethod.getSystemId(),
                evaluationMethod.getAssetId(), evaluationMethod.getLayerTargetId());
        if (CollectionUtils.isEmpty(evaluationMethods)) {
            return Result.failed(ResultCode.NOT_FOUND);
        }
        evaluationMethods.forEach(aem -> {
            aem.setMethod(evaluationMethod.getMethod());
            aem.setFinishState(state);
            aem.setModifyTime(LocalDateTime.now());
        });
        evaluationMethodRepository.saveAll(evaluationMethods);
        return Result.success();
    }

    private List<String> findUnitTargetNames(String systemId,List<AssetEvaluationMethodDO> evaluationMethods){
        return findUnitTargetData(systemId,evaluationMethods)
                .stream()
                .map(ItemData::getName)
                .toList();
    }

    private List<ItemData> findUnitTargetData(String systemId,List<AssetEvaluationMethodDO> evaluationMethods){
        Set<String> unitTargetIds = evaluationMethods.stream()
                .sorted(Comparator.comparingInt(AssetEvaluationMethodDO::getUnitTargetSort))
                .map(AssetEvaluationMethodDO::getUnitTargetId)
                .collect(Collectors.toSet());
        var unitTargets = systemTargetRepository.findAllBySystemIdAndKmTargetIdIn(systemId, unitTargetIds).stream()
                .sorted(Comparator.comparingInt(SystemTargetDO::getKmSort))
                .map(st->new ItemData(st.getKmName(),st.getKmTargetId()))
                .toList();
        var unitSpecialTargets = systemSpecialTargetRepository.findAllById(unitTargetIds).stream()
                .sorted(Comparator.comparingInt(SystemSpecialTargetDO::getSort))
                .map(st->new ItemData(st.getName(),st.getId()))
                .toList();
        return Stream.concat(unitTargets.stream(),unitSpecialTargets.stream()).toList();
    }

    private String getKmEvalMethod(String unitTargetId, RefTargetType refType, String method){
        var methodNames = Stream.of(StringUtils.split(method,BaseConstants.MULTI_SPLIT_CHAR))
                .map(item-> EvaluationMethod.fromMethod(ConvertUtils.toInteger(item)))
                .filter(em->em != EvaluationMethod.DEFAULT)
                .map(EvaluationMethod::getValue)
                .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        if(refType == RefTargetType.STANDARD){
            return String.join(BaseConstants.NEW_LINE,getKmEvalMethod(unitTargetId,methodNames));
        }else{
            var specialTarget = systemSpecialTargetRepository.findById(unitTargetId).orElse(null);
            if(Objects.isNull(specialTarget)
                    || specialTarget.getSpecialType() == SpecialType.CUSTOM
                    || StringUtils.isBlank(specialTarget.getKmTargetId())){
                return StringUtils.EMPTY;
            }
            return String.join(BaseConstants.NEW_LINE,getKmEvalMethod(specialTarget.getKmTargetId(),methodNames));
        }
    }

    private List<String> getKmEvalMethod(String kmUnitTargetId,String method){
        return this.kmEvaluationMethodRepository.findAllByUnitTargetId(kmUnitTargetId)
                .stream()
                .filter(em->{
                    var methods = StringUtils.split(em.getMethod(),BaseConstants.MULTI_SPLIT_CHAR);
                    return Stream.of(methods).anyMatch(m->StringUtils.contains(method,m));
                })
                .sorted(Comparator.comparingInt(KmEvaluationMethodDO::getSort))
                .map(KmEvaluationMethodDO::getContent)
                .toList();
    }

    public List<AssetEvaluationMethodDTO> findEvaluationMethod(@NonNull String systemId, @NonNull String assetId) {
        List<SystemTargetDO> systemTargets = this.systemTargetRepository.findAllBySystemId(systemId);
        List<AssetEvaluationMethodDO> evaluationMethods = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(systemId, assetId);
        if (CollectionUtils.isEmpty(systemTargets) || CollectionUtils.isEmpty(evaluationMethods)) {
            return new ArrayList<>();
        }
        return systemTargets.stream()
                .filter(st -> evaluationMethods.stream()
                        .anyMatch(em -> StringUtils.equals(st.getKmTargetId(), em.getLayerTargetId())))
                .sorted(Comparator.comparingInt(SystemTargetDO::getKmSort))
                .flatMap(layerTarget -> this.findEvaluationMethod(layerTarget, systemTargets, evaluationMethods).stream())
                .collect(Collectors.toList());
    }

    public void generateDefaultEvalMethod(@NonNull AssetDO assetDO) {
        List<SystemTargetDO> systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        if (CollectionUtils.isEmpty(systemTargets)) {
            log.warn("系统资产对象创建默认的与指标关联关系失败，未获取到系统指标数据");
            return;
        }
        AssetClassification classification = AssetClassification.fromId(assetDO.getClassId());
        if (Objects.isNull(classification)) {
            log.warn("未解析出系统资产对象所属分类，分类ID：".concat(assetDO.getClassId()));
            return;
        }
        if (classification == AssetClassification.MANAGE_DOC) {
            generateDefaultEvalMethod(assetDO, assetDO.getName().concat(ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX), systemTargets);
        } else {
            generateDefaultEvalMethod(assetDO, classification.getName().concat(ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX), systemTargets);
        }
    }

    public void generatePhySecurityEvalMethod(@NonNull AssetDO assetDO, final String reqContent) {
        List<SystemTargetDO> systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        if (CollectionUtils.isEmpty(systemTargets)) {
            log.warn("系统资产对象创建默认的与指标关联关系失败，未获取到系统指标数据");
            return;
        }
        List<String> targetNames = Stream.of(StringUtils.split(reqContent, AssetConstants.KEY_DATA_REQ_SPLIT))
                .filter(StringUtils::isNotBlank)
                .map(PhySecurityReqTargetRule::fromName)
                .filter(Objects::nonNull)
                .flatMap(rt -> rt.getTargetNames().stream())
                .collect(Collectors.toList());
        generateDefaultEvalMethod(assetDO, targetNames, AssetClassification.PHY_SECURITY, systemTargets);
    }

    public List<AssetEvaluationMethodDO> findPhySecurityEvalMethod(@NonNull String assetId, List<String> targetNames) {
        return findAssetEvalMethod(assetId, AssetClassification.PHY_SECURITY, targetNames);
    }

    public void modifyPhySecurityEvalMethod(@NonNull AssetDO assetDO, List<String> addTargetNames) {
        modifyAssetEvalMethod(assetDO, AssetClassification.PHY_SECURITY, addTargetNames);
    }

    public void generateSubBusinessEvalMethod(@NonNull AssetDO assetDO, final String reqContent) {
        List<SystemTargetDO> systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        if (CollectionUtils.isEmpty(systemTargets)) {
            log.warn("系统资产对象创建默认的与指标关联关系失败，未获取到系统指标数据");
            return;
        }
        List<String> targetNames = Stream.of(StringUtils.split(reqContent, AssetConstants.KEY_DATA_REQ_SPLIT))
                .filter(StringUtils::isNotBlank)
                .map(SubBusinessReqTargetRule::fromName)
                .filter(Objects::nonNull)
                .flatMap(rt -> rt.getTargetNames().stream())
                .collect(Collectors.toList());
        generateDefaultEvalMethod(assetDO, targetNames, AssetClassification.SUB_BUSINESS, systemTargets);
    }

    public List<AssetEvaluationMethodDO> findSubBusinessEvalMethod(@NonNull String assetId, List<String> targetNames) {
        return findAssetEvalMethod(assetId, AssetClassification.SUB_BUSINESS, targetNames);
    }

    public void modifySubBusinessEvalMethod(@NonNull AssetDO assetDO, List<String> addTargetNames) {
        modifyAssetEvalMethod(assetDO, AssetClassification.SUB_BUSINESS, addTargetNames);
    }

    public void generateKeyDataEvalMethod(@NonNull AssetDO assetDO, final String reqContent) {
        List<SystemTargetDO> systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        List<String> targetNames = Stream.of(StringUtils.split(reqContent, AssetConstants.KEY_DATA_REQ_SPLIT))
                .filter(StringUtils::isNotBlank)
                .map(KeyDataReqTargetRule::fromName)
                .filter(Objects::nonNull)
                .flatMap(rt -> rt.getTargetNames().stream())
                .collect(Collectors.toList());
        generateDefaultEvalMethod(assetDO, targetNames, AssetClassification.KEY_DATA, systemTargets);
    }

    public List<AssetEvaluationMethodDO> findKeyDataEvalMethod(@NonNull String assetId, List<String> targetNames) {
        return findAssetEvalMethod(assetId, AssetClassification.KEY_DATA, targetNames);
    }

    public void modifyKeyDataEvalMethod(@NonNull AssetDO assetDO, List<String> addTargetNames) {
        modifyAssetEvalMethod(assetDO, AssetClassification.KEY_DATA, addTargetNames);
    }

    private List<AssetEvaluationMethodDO> findAssetEvalMethod(@NonNull String assetId, @NonNull AssetClassification classification, List<String> targetNames) {
        AssetDO assetDO = assetRepository.findById(assetId).orElse(null);
        if (Objects.isNull(assetDO) || CollectionUtils.isEmpty(targetNames)) {
            return Collections.emptyList();
        }
        List<SystemTargetDO> systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        String constantName = classification.getName().concat(ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX);
        List<String> targetIds = this.constantRepository.findAllByNameOrderBySort(constantName)
                .stream().map(c -> getTargetByPath(c.getValue(), systemTargets))
                .filter(st -> Objects.nonNull(st) && targetNames.stream().anyMatch(name -> StringUtils.equals(st.getKmName(), name)))
                .map(SystemTargetDO::getKmTargetId)
                .toList();
        return evaluationMethodRepository.findAllBySystemIdAndAssetId(assetDO.getSystemId(), assetDO.getId())
                .stream()
                .filter(er -> targetIds.stream().anyMatch(id -> StringUtils.equals(er.getUnitTargetId(), id)))
                .collect(Collectors.toList());
    }

    private void modifyAssetEvalMethod(@NonNull AssetDO assetDO, @NonNull AssetClassification classification, List<String> addTargetNames) {
        if (CollectionUtils.isEmpty(addTargetNames)) {
            return;
        }
        var systemTargets = systemTargetRepository.findAllBySystemId(assetDO.getSystemId());
        if (CollectionUtils.isEmpty(systemTargets)) {
            log.warn("系统资产对象创建默认的与指标关联关系失败，未获取到系统指标数据");
            return;
        }
        List<AssetEvaluationMethodDO> sources = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(assetDO.getSystemId(), assetDO.getId());
        String reqContent = classification.getName().concat(ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX);
        try {
            List<AssetEvaluationMethodDO> createData = this.constantRepository.findAllByNameOrderBySort(reqContent)
                    .stream()
                    .map(c -> getTargetByPath(c.getValue(), systemTargets))
                    .filter(st -> Objects.nonNull(st) && addTargetNames.stream().anyMatch(name -> StringUtils.equals(st.getKmName(), name)))
                    .map(targetDO -> AssetEvaluationMethodDO.builder()
                            .systemId(assetDO.getSystemId())
                            .classId(assetDO.getClassId())
                            .assetId(assetDO.getId())
                            .unitTargetId(targetDO.getKmTargetId())
                            .layerTargetId(targetDO.getKmParentId())
                            .unitTargetSort(targetDO.getKmSort())
                            .method(getDefaultEvalMethod(targetDO))
                            .desc(getDefaultDesc(assetDO.getClassId()))
                            .build())
                    .filter(aem -> !checkEvaluationMethodExist(aem, sources))
                    .peek(aem -> aem.setCreateTime(LocalDateTime.now()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(createData)) {
                this.evaluationMethodRepository.saveAll(createData);
            }
        } catch (Exception ex) {
            log.error("添加重要数据资产对象默认关联指标信息出错：", ex);
        }
    }

    private boolean checkEvaluationMethodExist(@NonNull AssetEvaluationMethodDO data, List<AssetEvaluationMethodDO> sources) {
        if (CollectionUtils.isEmpty(sources)) {
            return false;
        }
        return sources.stream()
                .anyMatch(aem -> StringUtils.equals(data.getSystemId(), aem.getSystemId())
                        && StringUtils.equals(data.getClassId(), aem.getClassId())
                        && StringUtils.equals(data.getAssetId(), aem.getAssetId())
                        && StringUtils.equals(data.getUnitTargetId(), aem.getUnitTargetId()));
    }

    private void generateDefaultEvalMethod(AssetDO assetDO, List<String> targetNames, AssetClassification classification, List<SystemTargetDO> systemTargets) {
        String constantName = classification.getName().concat(ASSET_DEFAULT_TARGET_CONSTANT_SUFFIX);
        if (CollectionUtils.isEmpty(targetNames)) {
            generateDefaultEvalMethod(assetDO, constantName, systemTargets);
            return;
        }
        List<ConstantDO> constants = this.constantRepository.findAllByNameOrderBySort(constantName);
        if (CollectionUtils.isEmpty(constants)) {
            return;
        }
        List<AssetEvaluationMethodDO> sources = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(assetDO.getSystemId(), assetDO.getId());
        try {
            List<AssetEvaluationMethodDO> createData = constants.stream()
                    .map(c -> getTargetByPath(c.getValue(), systemTargets))
                    .filter(st -> Objects.nonNull(st) && targetNames.stream().anyMatch(name -> StringUtils.equals(st.getKmName(), name)))
                    .map(targetDO -> AssetEvaluationMethodDO.builder()
                            .systemId(assetDO.getSystemId())
                            .classId(assetDO.getClassId())
                            .assetId(assetDO.getId())
                            .unitTargetId(targetDO.getKmTargetId())
                            .layerTargetId(targetDO.getKmParentId())
                            .unitTargetSort(targetDO.getKmSort())
                            .method(getDefaultEvalMethod(targetDO))
                            .desc(getDefaultDesc(assetDO.getClassId()))
                            .build())
                    .peek(aem -> aem.setCreateTime(LocalDateTime.now()))
                    .filter(aem -> !checkEvaluationMethodExist(aem, sources))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(createData)) {
                this.evaluationMethodRepository.saveAll(createData);
            }
        } catch (Exception ex) {
            log.error("添加重要数据资产对象默认关联指标信息出错：", ex);
        }
    }

    private void generateDefaultEvalMethod(AssetDO assetDO, String constantName, List<SystemTargetDO> systemTargets) {
        List<ConstantDO> constants = this.constantRepository.findAllByNameOrderBySort(constantName);
        if (CollectionUtils.isEmpty(constants)) {
            return;
        }
        try {
            List<AssetEvaluationMethodDO> sources = this.evaluationMethodRepository.findAllBySystemIdAndAssetId(assetDO.getSystemId(), assetDO.getId());
            List<AssetEvaluationMethodDO> createData = constants.stream()
                    .map(c -> getTargetByPath(c.getValue(), systemTargets))
                    .filter(Objects::nonNull)
                    .map(targetDO -> AssetEvaluationMethodDO.builder()
                            .systemId(assetDO.getSystemId())
                            .classId(assetDO.getClassId())
                            .assetId(assetDO.getId())
                            .unitTargetId(targetDO.getKmTargetId())
                            .layerTargetId(targetDO.getKmParentId())
                            .unitTargetSort(targetDO.getKmSort())
                            .method(getDefaultEvalMethod(targetDO))
                            .desc(getDefaultDesc(assetDO.getClassId()))
                            .finishState(FinishState.NONE)
                            .build())
                    .filter(aem -> !checkEvaluationMethodExist(aem, sources))
                    .peek(aem -> aem.setCreateTime(LocalDateTime.now()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(createData)) {
                this.evaluationMethodRepository.saveAll(createData);
            }
        } catch (Exception ex) {
            log.error("添加资产默认关联指标信息出错：", ex);
        }
    }

    private SystemTargetDO getTargetByPath(String targetPath, List<SystemTargetDO> systemTargets) {
        String[] parse = StringUtils.split(targetPath, TargetConstants.MULTI_TARGET_SPLIT);
        if (parse.length < TargetConstants.UNIT_TARGET_PATH_POSITION) {
            return null;
        }
        String layerTargetName = parse[TargetConstants.LAYER_TARGET_PATH_POSITION];
        String unitTargetName = parse[TargetConstants.UNIT_TARGET_PATH_POSITION];
        String layerTargetId = systemTargets.stream()
                .filter(st -> st.getKmDeepness() == TargetDeepness.LAYER.getDeepness()
                        && StringUtils.equals(st.getKmName(), layerTargetName))
                .map(SystemTargetDO::getKmTargetId)
                .findFirst()
                .orElse("");
        if (StringUtils.isBlank(layerTargetId)) {
            return null;
        }
        return systemTargets.stream()
                .filter(st -> StringUtils.equals(st.getKmParentId(), layerTargetId)
                        && StringUtils.equals(st.getKmName(), unitTargetName))
                .findFirst()
                .orElse(null);
    }

    private List<AssetEvaluationMethodDTO> findEvaluationMethod(SystemTargetDO layerTarget, List<SystemTargetDO> systemTargets,
                                                                List<AssetEvaluationMethodDO> evaluationMethods) {
        return evaluationMethods.stream()
                .filter(em -> StringUtils.equals(em.getLayerTargetId(), layerTarget.getKmTargetId()))
                .sorted(Comparator.comparingInt(AssetEvaluationMethodDO::getUnitTargetSort))
                .map(EvaluationRangeMapper.INSTANCE::toDTO)
                .peek(em -> {
                    em.setTargetType(layerTarget.getKmType());
                    em.setLayerTarget(layerTarget.getKmName());
                    em.setUnitTarget(getTargetNameById(em.getUnitTargetId(), systemTargets));
                    em.setEvaTarget(getTargetNameByParentId(em.getUnitTargetId(), systemTargets));
                })
                .collect(Collectors.toList());
    }

    private Result<String> removeRelateTarget(RelatedTargetDTO relatedTarget, List<AssetEvaluationMethodDO> evaluationMethods) {
        List<AssetEvaluationMethodDO> deleteData = evaluationMethods.stream()
                .filter(aem -> relatedTarget.getUnitTargetIds()
                        .stream()
                        .noneMatch(unitTargetId -> StringUtils.equals(unitTargetId, aem.getUnitTargetId())))
                .collect(Collectors.toList());
        try {
            if (CollectionUtils.isNotEmpty(deleteData)) {
                this.processRelatedService.deleteAssetRelateTargetRelatedData(deleteData);
                this.evaluationMethodRepository.deleteAll(deleteData);
                this.processRelatedService.resetAssetRelateTargetRelateModuleProcess(deleteData);
            }
            return Result.success();
        } catch (Exception ex) {
            log.error("移除资产关联指标信息出错：", ex);
            return Result.failed(ResultCode.FAIL);
        }
    }

    private Result<String> createRelateTarget(RelatedTargetDTO relatedTarget, List<AssetEvaluationMethodDO> evaluationMethods) {
        List<String> createTargetIds = relatedTarget.getUnitTargetIds().stream()
                .filter(unitTargetId -> evaluationMethods.stream().noneMatch(aem -> StringUtils.equals(unitTargetId, aem.getUnitTargetId())))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(createTargetIds)) {
            return Result.success();
        }
        AssetDO assetDO = this.assetRepository.findById(relatedTarget.getAssetId()).orElse(null);
        if (Objects.isNull(assetDO)) {
            return Result.failed(ResultCode.NOT_FOUND);
        }
        try {
            var specialTargets = this.systemSpecialTargetRepository.findAllBySystemId(relatedTarget.getSystemId());
            var createData = createTargetIds.stream()
                    .filter(StringUtils::isNotBlank)
                    .map(unitTargetId -> this.systemTargetRepository.findBySystemIdAndKmTargetId(relatedTarget.getSystemId(),unitTargetId).orElse(null))
                    .filter(Objects::nonNull)
                    .map(targetDO -> AssetEvaluationMethodDO.builder()
                            .systemId(relatedTarget.getSystemId())
                            .classId(assetDO.getClassId())
                            .assetId(assetDO.getId())
                            .unitTargetId(targetDO.getKmTargetId())
                            .layerTargetId(targetDO.getKmParentId())
                            .unitTargetSort(targetDO.getKmSort())
                            .method(getDefaultEvalMethod(targetDO))
                            .desc(getDefaultDesc(assetDO.getClassId()))
                            .finishState(FinishState.NONE)
                            .refType(RefTargetType.STANDARD)
                            .build())
                    .peek(aem -> aem.setCreateTime(LocalDateTime.now()))
                    .collect(Collectors.toList());
            var createSpecialData = createTargetIds.stream()
                    .filter(StringUtils::isNotBlank)
                    .map(id->specialTargets.stream().filter(st->StringUtils.equals(st.getId(),id)).findFirst().orElse(null))
                    .filter(Objects::nonNull)
                    .map(sp-> AssetEvaluationMethodDO.builder()
                            .systemId(relatedTarget.getSystemId())
                            .classId(assetDO.getClassId())
                            .assetId(assetDO.getId())
                            .unitTargetId(sp.getId())
                            .layerTargetId(sp.getLayerTargetId())
                            .unitTargetSort(sp.getSort())
                            .finishState(FinishState.NONE)
                            .refType(RefTargetType.SPECIAL)
                            .build())
                    .peek(aem->aem.setCreateTime(LocalDateTime.now()))
                    .toList();
            if (CollectionUtils.isNotEmpty(createData)) {
                this.evaluationMethodRepository.saveAll(createData);
            }
            if(CollectionUtils.isNotEmpty(createSpecialData)){
                this.evaluationMethodRepository.saveAll(createSpecialData);
            }
            return Result.success();
        } catch (Exception ex) {
            log.error("添加资产关联指标信息出错：", ex);
            return Result.failed(ResultCode.FAIL);
        }
    }

    private String getTargetNameById(String targetId, List<SystemTargetDO> systemTargets) {
        return systemTargets.stream()
                .filter(st -> StringUtils.equals(st.getKmTargetId(), targetId))
                .map(SystemTargetDO::getKmName)
                .findFirst()
                .orElse("");
    }

    private String getTargetNameByParentId(String parentTargetId, List<SystemTargetDO> systemTargets) {
        return systemTargets.stream()
                .filter(st -> StringUtils.equals(st.getKmParentId(), parentTargetId))
                .map(SystemTargetDO::getKmName)
                .findFirst()
                .orElse("");
    }

    private String getDefaultEvalMethod(SystemTargetDO targetDO) {
        if (targetDO.getKmType() == TargetType.MANAGEMENT) {
            return EvaluationMethod.getManageEvaluationMethods()
                    .stream()
                    .map(EvaluationMethod::getMethod)
                    .map(String::valueOf)
                    .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        } else {
            return EvaluationMethod.getTechnologyEvaluationMethods()
                    .stream()
                    .map(EvaluationMethod::getMethod)
                    .map(String::valueOf)
                    .collect(Collectors.joining(BaseConstants.MULTI_SPLIT_CHAR));
        }
    }

    private String getDefaultDesc(String classId) {
        KmAssetClassDO classDO = this.kmAssetClassRepository.findById(classId).orElse(null);
        if (Objects.isNull(classDO)) {
            return "";
        }
        return DataUtils.findFirst(this.constantRepository.findByName(classDO.getName().concat(TEMPLATE_CONSTANT_SUFFIX)))
                .map(ConstantDO::getValue)
                .filter(StringUtils::isNotBlank)
                .orElse("");
    }

    private List<TreeNode> findAssetTree(List<String> assetClassIds, List<AssetDO> assetList, List<AssetEvaluationMethodDO> evaluationMethods) {
        return assetList.stream()
                .filter(a -> assetClassIds.stream().anyMatch(classId -> StringUtils.equals(a.getClassId(), classId)))
                .filter(a -> Objects.nonNull(a.getIsUse()) && a.getIsUse())
                .map(a -> TreeNode.builder()
                        .id(a.getId())
                        .name(AssetUtils.getAssetName(a))
                        .data(getAssetFinishState(a, evaluationMethods))
                        .build())
                .collect(Collectors.toList());
    }

    private FinishState getAssetFinishState(AssetDO assetDO, List<AssetEvaluationMethodDO> evaluationMethods) {
        List<AssetEvaluationMethodDO> query = evaluationMethods.stream()
                .filter(aem -> StringUtils.equals(aem.getAssetId(), assetDO.getId()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(query)) {
            return FinishState.NONE;
        }
        long finishCount = query.stream()
                .filter(aem -> aem.getFinishState() == FinishState.FINISH)
                .count();
        long noneCount = query.stream()
                .filter(aem -> aem.getFinishState() == FinishState.NONE)
                .count();
        if (noneCount == query.size()) {
            return FinishState.NONE;
        }
        return finishCount == query.size() ? FinishState.FINISH : FinishState.INCOMPLETE;
    }
}